package users

import (
	"fmt"
	"gitee.com/theegg/go-brick/app/model"
	"gitee.com/theegg/go-brick/app/model/user/user_accounts"
	"gitee.com/theegg/go-brick/app/model/user/user_logs"
	"gitee.com/theegg/go-brick/app/model/user/user_tree"
	"gitee.com/theegg/go-brick/app/service/app"
	"gitee.com/theegg/go-brick/app/service/help/cbcrypt"
	"gitee.com/theegg/go-brick/app/service/help/cjwt"
	"strconv"
	"time"
)

// 查询参数
type UserQueryParams struct {
	PageSize  string `form:"page_size" json:"page_size"  binding:"gte=0,lte=100" label:"每页数量"`
	PageIndex string `form:"page_index" json:"page_index"  binding:"gte=0,lte=99999" label:"当前页数"`
	UserName  string `form:"username" json:"username"  binding:"" label:"用户名"`
}

// 添加参数
type UserAddParams struct {
	Pid         int64  `form:"pid" binding:"omitempty,min=6,max=24" label:"上级ID"`
	Username    string `form:"username" binding:"required,min=6,max=24" label:"用户名"`
	Nickname    string `form:"nickname" binding:"required,customMin=6,customMax=18" label:"昵称"`
	Password    string `form:"password" binding:"required,min=6,max=24" label:"登陆密码"`
	SecPassword string `form:"sec_password" binding:"omitempty,min=6,max=24" label:"安全密码"`
	UserType    int    `form:"type_id" binding:"omitempty,oneof=1 2 3" label:"用户类型"`
	IsTester    int    `form:"is_tester" binding:"omitempty,oneof=0 1" label:"是否类型"`
	IsEditor    int    `form:"is_editor" binding:"omitempty,oneof=0 1" label:"是否编辑用户"`
	IP          string `form:"ip" binding:"-" label:"IP"`
}

// 资金流转参数
type UserFinanceParams struct {
	Id          int64  `form:"id" binding:"omitempty,number,gte=1,lte=999999999" label:"用户ID"`
	FlowType    string `form:"flow_type" binding:"required,oneof=in out" label:"流转类型"`
	FinanceType string `form:"finance_type" binding:"required,oneof=coin score" label:"资金类型"`
	SecPassword string `form:"sec_password" binding:"omitempty,min=6,max=24" label:"安全密码"`
	Amount      int64  `form:"amount" binding:"required,number,gte=10,lte=10000" label:"金额"`
}

// 用户冻结参数
type UserLockParams struct {
	Id          int64  `form:"id" binding:"omitempty,number,gte=1,lte=999999999" label:"用户ID"`
	LockType    int    `form:"lock_type" binding:"required,oneof=1 2 3 4 5" label:"冻结类型"`
	LockLevel   int    `form:"lock_level" binding:"required,oneof=1 2 3" label:"冻结目标"`
	SecPassword string `form:"sec_password" binding:"required,min=6,max=24" label:"安全密码"`
	LockReason  string `form:"lock_reason" binding:"required,min=2,max=32" label:"冻结原因"`
}

// join数据类型
type UserJoinUserAccounts struct {
	Users         `xorm:"extends"`
	Score         int64
	LockedScore   int64
	Balance       int64
	LockedBalance int64
}

// 非法用户锁定类型
var LockOptions = []map[string]string{
	0: {
		"value":    "1",
		"label_cn": "未冻结",
		"label_en": "Unlock",
	},
	1: {
		"value":    "2",
		"label_cn": "冻结登录",
		"label_en": "Lock Login",
	},
	2: {
		"value":    "3",
		"label_cn": "冻结购物",
		"label_en": "Lock Buy",
	},
	3: {
		"value":    "4",
		"label_cn": "冻结VIP",
		"label_en": "Lock Vip",
	},
	4: {
		"value":    "5",
		"label_cn": "冻结退款",
		"label_en": "Lock return",
	},
}

// 非法用户锁定深度
var LockLevelOptions = []map[string]string{
	0: {
		"value":    "1",
		"label_cn": "仅自己",
		"label_en": "Only Self",
	},
	1: {
		"value":    "2",
		"label_cn": "直接",
		"label_en": "Direct",
	},
	2: {
		"value":    "3",
		"label_cn": "所有",
		"label_en": "All",
	},
}

// 用户类型
var UserTypeOptions = []map[string]string{
	0: {
		"value":    "1",
		"label_cn": "VIP会员",
		"label_en": "VIP member",
	},
	1: {
		"value":    "2",
		"label_cn": "高级会员",
		"label_en": "Premium member",
	},
	2: {
		"value":    "3",
		"label_cn": "一般会员",
		"label_en": "Normal members",
	},
}

// vip 用户
const USER_TYPE_TOP_LEVEL = 1
const USER_TYPE_SECOND_LEVEL = 2
const USER_TYPE_THIRED_LEVEL = 3

// 分页获取所有数据
// @param params map 参数
// @return interface{}, error
func GetDataList(params map[string]interface{}) (map[string]interface{}, error) {
	returnData := make(map[string]interface{}, 0)

	queryParams, err := model.BuildAdminQueryParam(params)
	if err != nil {
		return returnData, nil
	}

	query := app.Db().Join("LEFT", "user_accounts", "user_accounts.user_id = users.id").
		Desc("users.id").Limit(queryParams.Limit, queryParams.Offset)

	// 查询用户名 == username
	if queryParams.Params["username"] != "" {
		query.Where("users.username = ?", queryParams.Params["username"])
	}

	userData := make([]UserJoinUserAccounts, 0)

	// 求总条数
	total, err := query.FindAndCount(&userData)
	if err != nil {
		return nil, app.NewError(err)
	}

	// 数据合成
	for i, v := range userData {
		userData[i].LockTypeName = GetLockName(v.LockType)
		userData[i].UserTypeName = GetUserTypeName(v.UserType)
	}

	returnData["data"] = userData
	returnData["total"] = total

	return returnData, nil
}

// 获取单个数据
// @param id int64 数据的id
// @return *Users, error
func GetItemById(id int64) (*Users, error) {
	user := new(Users)
	has, err := app.Db().ID(id).Get(user)

	if err != nil {
		return nil, app.NewError(err)
	}

	if !has {
		return nil, app.NewError("用户不存在")
	}

	return user, nil
}

// 是否存在用户
func HasUserFromName(username string) bool {
	user := new(Users)
	has, err := app.Db().Where("username = ?", username).Get(user)
	if err != nil {
		return false
	} else {
		if !has {
			return false
		}
	}

	return true
}

// 登陆用户
// params username 用户名
// params password 加密过的字符串
// return  user, bool
func UserLogin(username string, password string, ip string) (*Users, error) {
	user := new(Users)

	has, err := app.Db().Where("username = ?", username).Get(user)
	if err != nil {
		return user, err
	}

	if !has {
		return user, app.NewError("对不起, 用户名或者密码不存在")
	}

	// 检测密码
	if !cbcrypt.CheckEncode(user.Password, password) {
		fmt.Println(password)
		return user, app.NewError("对不起, 用户名或者密码不存在")
	}

	// 更新数据
	user.LastLoginTime = time.Now().Unix()
	user.LastLoginIp = ip
	affected, errUpdate := app.Db().ID(user.Id).Cols("last_login_ip", "last_login_time").Update(user)

	if errUpdate != nil {
		return user, errUpdate
	}

	if affected != 1 {
		return user, app.NewError("对不起, 更新用户数据失败")
	}

	return user, nil
}

// 根据用户生成token
func (u Users) GenToken() (string, error) {
	token, err := cjwt.NewTokenContainer("www").GenToken(EncodeUserId(u.Id))
	return token, err
}

// @title GetEditorUser
// @description 获取所有的编辑用户
func GetEditorUser() (map[int64]*Users, error) {
	user := make(map[int64]*Users)

	err := app.Db().Where("is_editor = ?", 1).Find(&user)

	if err != nil {
		return nil, err
	}

	return user, nil
}

// @title AddUserByAdmin
// @description 后台管理员添加用户
func AddUserByAdmin(params UserAddParams, adminId int64) error {
	return addUser(params, nil, adminId)
}

// @title AddUserByParent
// @description 用户添加用户
func AddUserByParent(params UserAddParams, parentUser *Users) error {
	return addUser(params, parentUser, 0)
}

// @title AddUser
// @description 添加用户
func addUser(params UserAddParams, parentUser *Users, adminId int64) error {

	// 1. 检测username 的唯一性
	if checkFieldUnique("username", params.Username) {
		return app.NewError("sorry, username already exist!")
	}

	// 2. 检测
	if params.UserType != USER_TYPE_TOP_LEVEL && parentUser == nil {
		return app.NewError("sorry, parent not exist!")
	}

	user := new(Users)

	if parentUser != nil {
		user.Pid = parentUser.Id
		user.Tid = parentUser.Tid
	} else {
		user.Pid = 0
		user.Tid = 0
	}

	user.Nickname = params.Nickname
	user.UserType = params.UserType
	user.IsTester = params.IsTester
	user.IsEditor = params.IsEditor
	user.Password = cbcrypt.Make(params.Password)
	user.Username = params.Username
	user.RegisterIp = params.IP
	user.RegisterTime = time.Now().Unix()
	user.AddAdminId = adminId
	user.LockType = 1

	// 开启事务
	session := app.Db().NewSession()
	defer session.Close()
	errSb := session.Begin()
	if errSb != nil {
		return app.NewError(errSb)
	}

	affected, errInsert := session.Insert(user)
	if errInsert != nil {
		session.Rollback()
		return app.NewError(errInsert)
	}

	if affected != 1 {
		session.Rollback()
		return app.NewError("对不起, 添加数据失败(0x001)")
	}

	// 刷新缓存
	if user.IsEditor == 1 {
		_, errDelete := DeleteEditorCache()
		if errDelete != nil {
			session.Rollback()
			return errDelete
		}
	}

	/** ======================= 初始化用户的账户 ====================== **/
	account := new(user_accounts.UserAccounts)
	account.UserId = user.Id
	account.Tid = user.Tid
	account.Pid = user.Pid
	account.Username = user.Username

	account.Score = 0
	account.Balance = 0
	affectedNewAccount, errNewAccount := session.Insert(account)
	if errNewAccount != nil {
		session.Rollback()
		return app.NewError(errNewAccount)
	}

	if affectedNewAccount != 1 {
		session.Rollback()
		return app.NewError("对不起, 添加数据失败(0x002)")
	}

	/** ======================= 初始化用户的树表 ====================== **/
	var frontTrees []*user_tree.UserTree
	var errFront error
	if parentUser != nil {
		// 1. 上级的树机构
		frontTrees, errFront = user_tree.GetAllFrontUser(parentUser.Id)
		if errFront != nil {
			session.Rollback()
			return app.NewError(errFront)
		}

		var userTreeData []user_tree.UserTree
		if len(frontTrees) > 0 {
			// 上级的前置树
			userTreeData = make([]user_tree.UserTree, len(frontTrees)+1)
			for index, item := range frontTrees {
				userTreeData[index].UserId = user.Id
				userTreeData[index].FrontUserId = item.FrontUserId
				userTreeData[index].Step = item.Step + 1
			}

			// 上级
			userTreeData[len(frontTrees)].UserId = user.Id
			userTreeData[len(frontTrees)].FrontUserId = parentUser.Id
			userTreeData[len(frontTrees)].Step = 1
		} else {
			// 上级
			userTreeData = make([]user_tree.UserTree, 1)
			userTreeData[0].UserId = user.Id
			userTreeData[0].FrontUserId = parentUser.Id
			userTreeData[0].Step = 1
		}

		affected, err := app.Db().Insert(userTreeData)
		if err != nil {
			session.Rollback()
			return app.NewError(err)
		}

		if affected != int64(len(userTreeData)) {
			session.Rollback()
			return app.NewError("对不起, 添加数据失败(0x003)")
		}
	}

	// 提交
	errCommit := session.Commit()
	if errCommit != nil {
		return errCommit
	}

	return nil
}

// 资金账户变更
func (u *Users) DoFinance(params UserFinanceParams, adminUserId int64) error {
	account, err := user_accounts.GetAccountByUserId(u.Id)
	if err != nil {
		return err
	}

	flowParams := make(map[string]interface{})
	flowParams["user_id"] = u.Id
	flowParams["amount"] = params.Amount
	flowParams["from_admin_id"] = adminUserId

	var errDo error
	if params.FlowType == "in" {
		if params.FinanceType == "coin" {
			errDo = account.DoFinanceAdminAddCoin(flowParams)
		} else {
			errDo = account.DoFinanceAdminAddScore(flowParams)
		}
	} else {
		if params.FinanceType == "coin" {
			errDo = account.DoFinanceAdminReduceCoin(flowParams)
		} else {
			errDo = account.DoFinanceAdminReduceCoin(flowParams)
		}
	}

	if errDo != nil {
		return errDo
	}

	return nil
}

// @title DoLock
// @description 锁定/解锁
func (u *Users) DoLock(params UserLockParams, adminUserId int64, ip string) error {

	// 检测lockType
	if !HasLockType(params.LockType) {
		return app.NewError("sorry, Lock type is not exist!")
	}

	// 检测lockLevel
	if !HasLockLevelType(params.LockLevel) {
		return app.NewError("sorry, Lock level type is not exist!")
	}

	var err error
	if params.LockLevel == 1 {
		_, err = app.Db().Table(new(Users)).ID(u.Id).Cols("lock_type").Update(map[string]int{"lock_type": params.LockType})
	} else if params.LockLevel == 2 {
		_, err = app.Db().Table(new(Users)).Where("pid = ?", u.Id).Or("id = ?", u.Id).Cols("lock_type").Update(map[string]int{"lock_type": params.LockType})
	} else {
		// 获取所有的后置id
		allIds, errBack := user_tree.GetAllBackUserIds(u.Id)
		if errBack != nil {
			return app.NewError(errBack)
		}
		allIds = append(allIds, u.Id)

		_, err = app.Db().Table(new(Users)).In("id", allIds).Cols("lock_type").Update(map[string]int{"lock_type": params.LockType})
	}

	if err != nil {
		return app.NewError(err)
	}

	// 记录 log
	logData := make(map[string]interface{})
	logData["user_id"] = u.Id
	logData["lock_reason"] = params.LockReason
	logData["lock_level"] = params.LockLevel
	logData["lock_type"] = params.LockType
	logData["admin_id"] = adminUserId
	logData["ip"] = ip

	errLog := user_logs.SaveLog(u.Id, 1, logData)
	if errLog != nil {
		return app.NewError(errLog)
	}

	return nil
}

// @title ModifyState
// @description 修改用户状态
func (u *Users) ModifyState() (bool, error) {
	state := 1
	if u.State == 1 {
		state = 0
	}

	affected, err := app.Db().Table(new(Users)).ID(u.Id).Cols("state").Update(map[string]int{"state": state})

	if err != nil {
		return false, app.NewError(err)
	}

	// 生效条数
	if affected == 0 {
		return false, app.NewError("对不起, 指定的ID更新数量不正确")
	}

	return true, nil
}

/** =============================  辅助函数 ============================= */
// 检测字段唯一性
func checkFieldUnique(field string, value interface{}) bool {
	user := new(Users)

	has, err := app.Db().Where(field+" = ?", value).Get(user)

	if err != nil {
		panic(err.Error())
		return false
	} else {
		if !has {
			return false
		}
	}

	return true
}

// 冻结原因选项
func GetLockOptions(options ...string) []map[string]string {
	countryStr := "cn"
	if len(options) > 0 && options[0] != "" {
		countryStr = options[0]
	}

	fieldName := "label_" + countryStr

	var data = make([]map[string]string, len(LockOptions))
	for i, item := range LockOptions {
		data[i] = map[string]string{"value": item["value"], "label": item[fieldName]}
	}

	return data
}

// 冻结深度选项
func GetLockLevelOptions(options ...string) []map[string]string {
	countryStr := "cn"
	if len(options) > 0 && options[0] != "" {
		countryStr = options[0]
	}

	fieldName := "label_" + countryStr

	var data = make([]map[string]string, len(LockLevelOptions))
	for i, item := range LockLevelOptions {
		data[i] = map[string]string{"value": item["value"], "label": item[fieldName]}
	}

	return data
}

// 冻结原因 name
func GetLockName(lockType int, options ...string) string {
	countryStr := "cn"
	if len(options) > 0 && options[0] != "" {
		countryStr = options[0]
	}

	fieldName := "label_" + countryStr

	name := ""
	for _, item := range LockOptions {
		intTypeVal, _ := strconv.Atoi(item["value"])
		if lockType == intTypeVal {
			name = item[fieldName]
		}
	}

	return name
}

// 用户类型选项
func GetTypeOptions(options ...string) []map[string]string {
	countryStr := "cn"
	if len(options) > 0 && options[0] != "" {
		countryStr = options[0]
	}

	fieldName := "label_" + countryStr

	var data = make([]map[string]string, len(UserTypeOptions))
	for i, item := range UserTypeOptions {
		data[i] = map[string]string{"value": item["value"], "label": item[fieldName]}
	}

	return data
}

// 用户类型 name
func GetUserTypeName(lockType int, options ...string) string {
	countryStr := "cn"
	if len(options) > 0 && options[0] != "" {
		countryStr = options[0]
	}

	fieldName := "label_" + countryStr

	name := ""
	for _, item := range UserTypeOptions {
		intTypeVal, _ := strconv.Atoi(item["value"])
		if lockType == intTypeVal {
			name = item[fieldName]
		}
	}

	return name
}

// 是否存在lockType
func HasLockType(lockType int) bool {
	res := false
	for _, item := range LockOptions {
		intTypeVal, _ := strconv.Atoi(item["value"])
		if lockType == intTypeVal {
			res = true
		}
	}
	return res
}

// 是否存在lockLevelType
func HasLockLevelType(lockLevelType int) bool {
	res := false
	for _, item := range LockLevelOptions {
		intTypeVal, _ := strconv.Atoi(item["value"])
		if lockLevelType == intTypeVal {
			res = true
		}
	}
	return res
}

/** ========================== ================================== */
var deflect int64 = 3002192

func EncodeUserId(userId int64) int64 {
	return userId*7 + deflect
}

func DecodeUserId(userId int64) (int64, error) {
	if (userId-deflect)%7 != 0 {
		return 0, fmt.Errorf("无效的token(0x002)")
	}

	return (userId - deflect) / 7, nil
}

// @title TableName
// @description join 数据类型必须返回一个主表的　表名
func (UserJoinUserAccounts) TableName() string {
	return "users"
}
